//////////////////////////////////////////////////////////////////////////////
//
// TinyCl - TinyCl Definitions
// tinycl.h
//
// Copyright (C) 2007-2008 by Project Vogue.
// Written by Yoshifumi "VOGUE" INOUE. (yosi@msn.com)
//
// @(#)$Id: //proj/evedit2/mainline/tinycl/tinycl_kernel.h#16 $
//
#if !defined(INCLUDE_tinycl_kernel_h)
#define INCLUDE_tinycl_kernel_h

namespace TinyCl
{

class Frame;
class Thread;

// Objects in lisp heap.
template<class T>
class HeapObject_ : public T
{
    public:  void* operator new(size_t, void* pv) { return pv; }
    private: void operator delete(void*) {}
}; // HeapObject

//////////////////////////////////////////////////////////////////////
//
// Executive
//
class Executive
{
    private: static Executive* sm_pExecutive;

    private: Thread* m_pFirstThread;
    private: Thread* m_pLastThread;

    // ctor
    public: Executive() :
        m_pFirstThread(NULL),
        m_pLastThread(NULL)
    {
        ASSERT(NULL == sm_pExecutive);
        sm_pExecutive = this;
    } // Executive

    // [A]
    public: Thread* AddThread(Thread*);

    // [E]
    public: class EnumThread
    {
        private: Thread* m_pRunner;

        public: EnumThread(const Executive* p) :
            m_pRunner(p->m_pFirstThread) {}

        public: bool    AtEnd() const { return NULL == m_pRunner; }
        public: Thread* Get()   const { ASSERT(!AtEnd()); return m_pRunner; }
        public: void    Next();
    }; // EnumThread

    // [G]
    public: static Executive* Get()
        { return sm_pExecutive; }
}; // Executive

//////////////////////////////////////////////////////////////////////
//
// Frame
//
class Frame : public AsInt
{
    public: enum Type
    {
        Type_Invalid,

        // For loading FASL generated by EVCL3, below type code must be as
        // same as evcl3.
        Type_Bind           = 0x424E4400,   // BND
        Type_Block          = 0x424C4B00,   // BLK
        Type_Catch          = 0x43415400,   // CAT
        Type_Finally        = 0x464C5900,   // FLY
        Type_FromForeign    = 0x46724600,   // FrF
        Type_Function       = 0x46756E00,   // Fun
        Type_GcDisable      = 0x47634400,   // GcD
        Type_GcRoot         = 0x47635200,   // GcR
        Type_Handler        = 0x48645200,   // HdR
        Type_ObStack        = 0x4F625300,   // ObS
        Type_ToKernel       = 0x4B724E00,   // KrN
        Type_Tagbody        = 0x54425900,   // TBY
        Type_ToForeign      = 0x546F4600,   // ToF
        Type_TryCatch       = 0x54725900,   // Try
    }; // Type

    public: Frame*  m_pOuter;
    public: Int     m_eFrame;

    protected: Frame(Type e = Type_Invalid, Frame* pOuter = NULL) :
        m_eFrame(e),
        m_pOuter(pOuter) {}

    public: template<typename T> T* DynamicCast() const
    {
        unless (Is<T>()) return NULL;
        return reinterpret_cast<T*>(const_cast<Frame*>(this));
    } // DynamicCast

    public: template<typename T> bool Is() const
        { return T::Type_() == m_eFrame; }

    public: template<typename T> T* StaticCast() const
    {
        ASSERT(Is<T>());
        return reinterpret_cast<T*>(const_cast<Frame*>(this));
    } // StaticCast
}; // Frame

class RaSlot;

/// <summary>
///   FunctionFrame represents function call information in the stack of
///   thread.
/// </summary>
class FunctionFrame : public Frame
{
    public: static Type Type_() { return Type_Function; }

    public: Val     m_fn;
    public: Int     m_nCodeIndex;
    public: RaSlot* m_pEnd;
    public: RaSlot* m_pRa;
    public: void*   m_pStart;
    public: Val*    m_pval;

    public: FunctionFrame() :
        Frame(Type_Function),
        m_fn(nil),
        m_pEnd(NULL),
        m_pRa(NULL),
        m_pStart(NULL),
        m_pval(NULL) {}

    public: bool HasFrame(Frame* pFrame) const
    {
        return pFrame > reinterpret_cast<Frame*>(m_pStart) &&
               pFrame < reinterpret_cast<Frame*>(m_pEnd);
    } // HasFrame
}; // FunctionFrame

struct InitParams;

/// <summary>
///   Represents lisp thread.
/// </summary>
class Thread : public Record_<Thread, Layout_thread>
{
    friend class Executive;

    public: static Val ClassD_() { return CLASSD_thread; }

    public: void* operator new(size_t);

    // Thread Id
    protected: static Int sm_nThread;

    private: Thread* m_pNext;
    private: Thread* m_pPrev;

    public: Val m_id;

    // FIXME 2008-01-06 yosi@msn.com We should use Mm::AreaManager.
    public: Mm::Area*    m_pBinoArea;
    public: Mm::Area*    m_pCodeArea;
    public: Mm::Area*    m_pConsArea;
    public: Mm::Area*    m_pDataArea;

    public: Val m_fp;
    public: Val m_fn;
    public: Val m_n;
    public: Val mv_value[Arch::MultipleValuesLimit];
    public: Val mv_tlv[Arch::TlvLimits];
    public: Val mv_size[128];
    public: Val mv_count[128];

    // ctor
    public: Thread(Val);

    // [A]
    public: Val AllocBinObj(Val);
    public: Val AllocBinVec(Val, Val);
    public: Val AllocCode(Val, size_t);
    public: Val AllocCons(Val, Val);
    public: Val AllocRecord(Val);
    public: Val AllocInstance(Val);
    public: Val AllocStorage(Val);
    public: Val AllocVector(Val, Val);

    // [E]
    public: class EnumFrame
    {
        private: Frame* m_p;

        public: EnumFrame(Thread* pth) :
            m_p(reinterpret_cast<Frame*>(pth->m_fp)) {}

        public: bool   AtEnd() const { return NULL == m_p; }
        public: Frame* Get()   const { ASSERT(!AtEnd()); return m_p; }

        public: void   Next()
            { ASSERT(!AtEnd()); m_p = m_p->m_pOuter; }
    }; // EnumFrame

    class EnumStack
    {
        private: FunctionFrame  m_oFunFrame;
        private: Frame*         m_p;

        public: EnumStack(const Thread* pth) :
            m_p(pth->m_fp->To<Frame>()) {}

        public: bool   AtEnd() const { return NULL == m_p; }
        public: Frame* Get()   const { ASSERT(!AtEnd()); return m_p; }
        public: void   Next();

        private: void setupFunFrame(RaSlot*, Frame*);
    }; // EnumStack

    public: class EnumValue
    {
        private: Val* m_pEnd;
        private: Val* m_p;

        public: EnumValue(Thread* pt) :
            m_pEnd(pt->mv_value + Fixnum::Decode_(pt->m_n)),
            m_p(pt->mv_value) {}

        public: bool AtEnd() const { return m_p >= m_pEnd; }
        public: Val  Get()   const { ASSERT(!AtEnd()); return *m_p; }
        public: void Next()        { ASSERT(!AtEnd()); m_p++; }
    }; // EnumValue

    public: class EnumValueReverse
    {
        private: Val* m_pEnd;
        private: Val* m_p;

        public: EnumValueReverse(Thread* pt) :
            m_pEnd(pt->mv_value),
            m_p(pt->mv_value  + Fixnum::Decode_(pt->m_n) - 1) {}

        public: bool AtEnd() const { return m_p < m_pEnd; }
        public: Val  Get()   const { ASSERT(!AtEnd()); return *m_p; }
        public: void Next()        { ASSERT(!AtEnd()); --m_p; }
    }; // EnumValueReverse

    // [G]
    public: static Thread* Get();

    public: uint GetId() const
        { return static_cast<uint>(Fixnum::Decode_(m_id)); }

    // [P]
    public: static Thread* PlatformStart(const InitParams*);   // arch
    public: void PlatformRestart();

    // [R]
    public: void Reset();
    public: void ResetAlloc();
    public: void Restart();

    // [S]
    public: void Start();

    // [T]
    public: Val* TlvPtr(Int iIndex)
        { return &mv_tlv[iIndex]; }

    public: static Val* TlvPtr_(Int iIndex)
        { return Get()->TlvPtr(iIndex); }

    // [U]
    public: void Unwinds(Frame*, bool = false);

    // [V]
    public: Val ValuesFromList(Val);
    public: Val ValuesToList(int = 0) const;
}; // Thread

/// <summary>
///   Lisp variable binding frame. This frame contains location of variable
///   values and values for restoring.
/// </summary>
class BindFrame : Frame
{
    public: static Type Type_() { return Type_Bind; }

    public: struct Entry
    {
        Val m_name;
        Val m_value;

        Val GetCell() const;
    }; // Entry

    public: Val m_n;

    /// <summary>
    ///   Construct bind frame with outer frame pointer.
    /// </summary>
    public: BindFrame(Frame* p) :
        Frame(Type_(), p) {}

    /// <summary>
    ///   Enumerator of variable location and previous value pair in bind
    ///   frame.
    /// </summary>
    public: class EnumEntry
    {
        private: Entry* m_p;
        private: Entry* m_pEnd;

        public: EnumEntry(const BindFrame* p) :
            m_p(p->getEntryStart()),
            m_pEnd(p->getEntryEnd()) {}

        public: bool   AtEnd() const { return m_p == m_pEnd; }
        public: Entry* Get() const { ASSERT(!AtEnd()); return m_p; }
        public: void   Next() { ASSERT(!AtEnd()); m_p++; }
    }; // Enum

    private: Entry* getEntryEnd() const
        { return getEntryStart() + Fixnum::Decode_(m_n); }

    private: Entry* getEntryStart() const
        { return reinterpret_cast<Entry*>(const_cast<BindFrame*>(this)+1); }

    /// <summary>
    ///   Restors previous value of each variables and thread frame pointer.
    /// </summary>
    public: void Pop()
    {
        Thread* pth = Thread::Get();
        Unwind(pth);
        pth->m_fp = Fixnum::Encode(m_pOuter);
    } // Pop

    public: void Unwind(Thread*);
}; // BindFrame

// <summary>
//   Helper class for constructing/destructing bind frame in C++ methods
//   and functions.
// </summary>
template<int t_n>
class BindFrameScope_
{
    private: BindFrame           m_oFrame;
    private: BindFrame::Entry    m_rgoEntry[t_n];
    private: BindFrame::Entry*   m_p;

    public: BindFrameScope_() :
        m_oFrame(Thread::Get()->m_fp->To<Frame>()),
        m_p(m_rgoEntry)
    {
        m_oFrame.m_n        = Fixnum::Encode(t_n);
        Thread::Get()->m_fp = Fixnum::Encode(&m_oFrame);
    } // BindFrameScope

    public: ~BindFrameScope_()
    {
        ASSERT(&m_rgoEntry[t_n] == m_p);
        m_oFrame.Pop();
    } // ~BindFrameScope_

    public: void Bind(int iTlv, Val new_value)
    {
        ASSERT(m_p - m_rgoEntry < t_n);

        Int ofsTlv = offsetof(Thread, mv_tlv[iTlv]);
        m_p->m_name  = reinterpret_cast<Val>(ofsTlv);

        Val* pTlv = Thread::TlvPtr_(iTlv);
        m_p->m_value = *pTlv;

        *pTlv = new_value;
        m_p++;
    } // Bind
}; // BindFrameScope

class GcDisableFrame : public Frame
{
    public: static Type Type_() { return Type_GcDisable; }
}; // GcDisableFrame


/// <summary>
///   Host parsers function frame.
/// </summary>
class Host
{
    public: static size_t ComputeFunFrameSize(Val, const RaSlot*);
    public: static Val    MapRaToFn(const RaSlot*);
}; // Host

class ObStackScope : public Frame
{
    public: static Type Type_() { return Type_ObStack; }

    public: ~ObStackScope() {}
}; // ObStackScope

#define TLV(mp_name) \
    ( *Thread::TlvPtr_(TLV_ ## mp_name) )

} // TinyCl

#endif //!defined(INCLUDE_tinycl_kernel_h)
